/* 魔塔游戏项目 */
#ifndef __OBJECT_H_
#define __OBJECT_H_

#include <fstream>
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include "Shop.h"
#include <unistd.h>

using namespace std;

/* 宏定义：获取函数及建立函数 */
#define DEFINE_SET_GET(name,type) type Get##name()const{return name;} void Set##name(const type& name){this->name = name;}    

/* =======================================================棋盘======================================================= */
class Point
{
public:
/* 构造函数 */
    Point():X(0),Y(0){}
    Point(int x, int y):X(x),Y(y){}
/* 宏定义函数 */
    DEFINE_SET_GET(X,int);
    DEFINE_SET_GET(Y,int);

private:
/* 棋盘成员变量 */
    int X;  //坐标位置
    int Y;
};

/* ======================抽象对象：玩家和怪兽的公共参数及函数====================== */
class VirtualObject:public Point    //继承棋盘类
{
public:
/* 构造函数及初始化 */
    VirtualObject():Point(), HP(0), Attack(0),Defends(0){}
    VirtualObject(int x, int y,const std::string& Name,const std::string& Symbol,int Hp = 0,int Attack = 0, int Defends = 0, int Exp = 0,int Money = 0)
        :Point(x, y),Name(Name),Symbol(Symbol),HP(Hp),Attack(Attack),Defends(Defends),Exp(Exp),Money(Money){}
/* 宏定义函数 */
    DEFINE_SET_GET(Name,std::string);       //名字
    DEFINE_SET_GET(HP,int);                 //血条
    DEFINE_SET_GET(Attack,int);             //攻击力
    DEFINE_SET_GET(Defends,int);            //防御力
    DEFINE_SET_GET(Symbol,std::string);     //标志
    DEFINE_SET_GET(Exp,int);                //经验值
    DEFINE_SET_GET(Money,int);

private:
/* 抽象类成员变量 */
    std::string Name;       //名字
    int HP;                 //血条
    int Attack;             //攻击力
    int Defends;            //防御力
    std::string Symbol;     //标志
    int Exp;                //经验值
    int Money;
};

/* 商店及背包的前置声明：声明之后，才能够在玩家类中识别 */
class Prop;
class Bag;  
class Scene;
using PropPtr = std::shared_ptr<Prop>;  //智能指针
/* ======================玩家类====================== */
class Player:public VirtualObject       //继承抽象对象类
{
public:
/* 构造函数 */
    Player():VirtualObject(){}
    Player(int x, int y,const std::string& Name,const std::string& Symbol, int HP, int Attack, int Defends,int Exp,int Money);
/* 析构函数 */
    ~Player();
/* 宏定义 */
    
    DEFINE_SET_GET(Level,int);
    
/* 添加行为函数 */
    Bag* GetBag(); 
    void OpenBag();
    void Move(Scene & s);        //移动函数
    void show();        //打印
    void LevelUp();     //提升等级
    
    void SavePlayerData(const std::string& filePath) const {
        std::ofstream fout(filePath);
        if (!fout.is_open()) {
            std::cerr << "Failed to open file for saving: " << filePath << std::endl;
            return;
        }
        fout << "PlayerInfo" << std::endl;
        fout << GetName() << endl;
        fout << GetHP() << endl;
        fout << GetMoney() << endl;
        fout << GetAttack() << endl;
        fout << GetDefends() << endl;
        fout << GetLevel() << endl;
        fout << GetExp() << endl;
        fout << GetSymbol() << endl;
        fout << GetX() << endl;
        fout << GetY() << endl;
        fout.close();
        //std::cout << "Player data saved successfully to " << filePath << std::endl;
    }

    // 其他需要的成员函数和数据成员
 
private:
/* 玩家类的成员变量 */
    int Level;          //等级
    Bag *b;             //书包
    std::vector<PropPtr> props;
};

/* ======================怪兽类====================== */
class Monster:public VirtualObject      //继承抽象对象类
{
public:
/* 构造函数及初始化 */
    Monster():VirtualObject(){}
    Monster(int x, int y,const std::string& Name,const std::string& Symbol, int HP, int Attack, int Defends,int Exp,int Money);
/* 打印 */
    void show();

// void SaveMonsterData(const std::string& filePath)  
void SaveMonsterData(std::ofstream& fout)
{
//         std::ofstream fout(filePath, std::ios::app);
//         if (!fout.is_open()) {
//             std::cerr << "Failed to open file for saving: " << filePath << std::endl;
//             return;
//         }
        fout << "MonsterInfo" << std::endl;
        fout << GetName() << endl;
        fout << GetHP() << endl;
        fout << GetMoney() << endl;
        fout << GetAttack() << endl;
        fout << GetDefends() << endl;
        fout << GetExp() << endl;
        fout << GetSymbol() << endl;
        fout << GetX() << endl;
        fout << GetY() << endl;
        // fout.close();
        //std::cout << "Monster data saved successfully to " << filePath << std::endl;
    }

    DEFINE_SET_GET(MaxHP,int);
   
private:
    int MaxHP;      //血条!!
};
/*    宝箱类     */
class TreasureBox:public VirtualObject
{
public:
    TreasureBox():VirtualObject(){}
    TreasureBox(int x, int y, const std::string& Name,const std::string& Symbol, int Money, int HP, int Attack, int Defends):VirtualObject(x, y, Name,Symbol, Money, HP, Attack, Defends){}
    
    void SaveTreasureBoxData(const std::string& filePath) 
    {
        
        std::ofstream fout(filePath, std::ios::app);
        if (!fout.is_open()) 
        {
            std::cerr << "Failed to open file for saving: " << filePath << std::endl;
            return;
        }
        fout << "TreasureBoxInfo" << std::endl;
        fout << GetName() << endl;
        fout << GetX() << endl;
        fout << GetY() << endl;
        fout << GetAttack() << endl;
        fout << GetDefends() << endl;
        fout << GetHP() << endl;
        fout << GetMoney() << endl;
        fout << GetSymbol() << endl;
        fout.close();
        //std::cout << "Treasure box data saved successfully to " << filePath << std::endl;
    }

};



/* ==============================================================商店类============================================================== */
class Prop
{
public:
    Prop():GoodsMoney(0){}
    Prop(int goodsMoney,std::string goodsName):GoodsMoney(goodsMoney),GoodsName(goodsName){}
    DEFINE_SET_GET(GoodsMoney,int);
    DEFINE_SET_GET(GoodsName,std::string);
    
    virtual ~Prop() = default;
  
private:
    int GoodsMoney;          //所需金钱
    std::string GoodsName;
};

/* ======================武器类====================== */
class Weapon:public Prop
{
public:
    Weapon():Prop(){}
    Weapon(int goodsMoney,std::string goodsName,int attack = 0)
        :Prop(goodsMoney,goodsName){}
    DEFINE_SET_GET(Attack,int);
private:
    int Attack;         //增加攻击力
    
};

/* ======================防御类====================== */
class Defend:public Prop 
{
public:
    DEFINE_SET_GET(Defends,int);
private:
    int Defends;        //增加防御能力
};

/* ======================药包类====================== */
class Medicine:public Prop
{
public:
    DEFINE_SET_GET(HP,int);
private:
    int HP;             //回血能力
};

/* ==================================================================背包类================================================================== */

class Bag   //多态，哪里是多态
{
public:
using PropPtr = std::shared_ptr<Prop>;  //智能指针
    //插入
    void Insert(const PropPtr & p);
    //输出
    void show();
    void ClearProps()
    {
        props.clear();
    }
    //取出//返回技能点
    PropPtr Equip(int index);
    //从背包中指定删除//返回金钱值
    int Sale(int index);

    const std::vector<PropPtr> &GetProps() const
    {
    return props;//返回背包中的道具
    }

    void Discard(int index)
    {
        if (index < 1 || index > props.size())
            return; // 越界访问，直接返回
        
        props.erase(props.begin()+(index - 1)); // 从背包中移除道具
    }

    void Save(const std::string& filename) const 
    {
        std::ofstream fout(filename);
        if (!fout.is_open()) {
            std::cerr << "无法打开文件进行保存: " << filename << std::endl;
            return;
        }

        for (const auto& prop : props) {
            fout << prop->GetGoodsName() << "," << prop->GetGoodsMoney() << std::endl;
            // fout << "BagInfo" << std::endl;
            // fout << prop->GetGoodsName() << endl;
            // fout << prop->GetGoodsMoney()<< endl;
            // // 根据 PropPtr 的定义添加其他属性的保存
        }

        fout.close();
        std::cout << "背包保存成功：" << filename << std::endl;
    }
    

private:
    std::vector<PropPtr> props; 
};

#endif